package com.accesshollywood.xmas2011.core;

import static playn.core.PlayN.assetManager;
import static playn.core.PlayN.graphics;

import java.util.ArrayList;

import org.jbox2d.callbacks.ContactImpulse;
import org.jbox2d.callbacks.ContactListener;
import org.jbox2d.callbacks.DebugDraw;
import org.jbox2d.collision.Collision;
import org.jbox2d.collision.Collision.PointState;
import org.jbox2d.collision.Manifold;
import org.jbox2d.collision.WorldManifold;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.Fixture;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.World;
import org.jbox2d.dynamics.contacts.Contact;

import playn.core.CanvasLayer;
import playn.core.DebugDrawBox2D;
import playn.core.Image;
import playn.core.ImageLayer;

public class Master {
	static final float	DPI					= 72.0f;
	static final float	worldScale			= DPI / 2.0f;
	static final float	timeStep			= 1.0f / 60.0f;
	static final int	velocityIterations	= 6;
	static final int	positionIterations	= 2;

	Vec2				gravity;
	boolean				doSleep;
	World				world;

	ArrayList<Body>		bodies;

	CanvasLayer			debugCanvas;

	public Master() {
		graphics().setSize(800, 400);
		gravity = new Vec2(0.0f, -10.0f);
		doSleep = true;

		world = new World(gravity, doSleep);

		bodies = new ArrayList<Body>();

		createBG();
		bodies.add(createGround());
		bodies.add(createGift());
		bodies.add(createBilly());
		createDebug();
		
		world.setContactListener(new MyContactListener());
	}

	public void createBG() {
		Image skinImage = assetManager().getImage("images/bg.png");
		ImageLayer skin = graphics().createImageLayer(skinImage);
		graphics().rootLayer().add(skin);
	}

	public Body createGround() {
		BodyDef bodyDef = new BodyDef();

		bodyDef.position.set(400 / Master.worldScale, -375 / Master.worldScale);
		bodyDef.userData = new Billboard("images/ground.png");
		Body body = world.createBody(bodyDef);
		((Billboard) body.getUserData()).parentBody = body;
		((Billboard) body.getUserData()).maxHitPoints = -1;
		((Billboard) body.getUserData()).currHitPoints = -1;
		
		PolygonShape box = new PolygonShape();
		box.setAsBox(800 / DPI, 75 / DPI);

		body.createFixture(box, 0.0f);

		return body;
	}

	public Body createGift() {
		BodyDef bodyDef = new BodyDef();
		bodyDef.type = BodyType.DYNAMIC;
		bodyDef.position.set(400 / Master.worldScale, -225 / Master.worldScale);
		bodyDef.userData = new Billboard("images/gift.png");
		Body body = world.createBody(bodyDef);
		((Billboard) body.getUserData()).parentBody = body;
		((Billboard) body.getUserData()).maxHitPoints = 10;
		((Billboard) body.getUserData()).currHitPoints = 10;
		PolygonShape box = new PolygonShape();
		box.setAsBox(65 / DPI, 65 / DPI);

		body.createFixture(box, 0.0f);

		return body;
	}

	public Body createBilly() {// 48x65
		BodyDef bodyDef = new BodyDef();
		bodyDef.type = BodyType.DYNAMIC;
		bodyDef.position.set(400 / Master.worldScale, 0 / Master.worldScale);
		bodyDef.angle = -40.0f;
		bodyDef.userData = new Billboard("images/billyHead_small2.png");

		Body body = world.createBody(bodyDef);

		((Billboard) body.getUserData()).parentBody = body;
		((Billboard) body.getUserData()).maxHitPoints = -1;
		((Billboard) body.getUserData()).currHitPoints = -1;

		PolygonShape dynamicBox = new PolygonShape();

		Vec2[] vertices;
		vertices = new Vec2[8];
		vertices[0] = new Vec2(0 / DPI, -65f / DPI);
		vertices[1] = new Vec2(24 / DPI, -48f / DPI);
		vertices[2] = new Vec2(48 / DPI, 0 / DPI);
		vertices[3] = new Vec2(36 / DPI, 48f / DPI);
		vertices[4] = new Vec2(0 / DPI, 65 / DPI);
		vertices[5] = new Vec2(-36 / DPI, 48f / DPI);
		vertices[6] = new Vec2(-48 / DPI, 0 / DPI);
		vertices[7] = new Vec2(-24 / DPI, -48f / DPI);
		dynamicBox.set(vertices, vertices.length);// .setAsBox(48/DPI, 65/DPI);
		// billy.setTransform(new Vec2(4,0), 45);

		FixtureDef fixtureDef = new FixtureDef();
		fixtureDef.shape = dynamicBox;
		fixtureDef.density = 1.0f;
		fixtureDef.friction = 0.3f;

		body.createFixture(fixtureDef);

		return body;
	}

	public void createDebug() {
		debugCanvas = graphics().createCanvasLayer(800, 400);
		DebugDrawBox2D myDebug = new DebugDrawBox2D();
		myDebug.setFlags(DebugDraw.e_shapeBit);
		myDebug.setFlipY(true);
		myDebug.setCanvas(debugCanvas);
		myDebug.setCameraScale(Master.worldScale);
		graphics().rootLayer().add(debugCanvas);
		world.setDebugDraw(myDebug);
	}

	public void update() {
		world.step(timeStep, velocityIterations, positionIterations);

		for (Body currBody : bodies) {
			((Billboard) currBody.getUserData()).update();
		}

		debugCanvas.canvas().clear();
		world.drawDebugData();

		checkForDestruction();
		
	}
	
	public void checkForDestruction(){
		for (Body currBody : bodies) {
			if(((Billboard) currBody.getUserData()).isBroken()){
				//bodies.remove(currBody);
			}
		}
	}


	public class MyContactListener implements ContactListener {

		@Override
		public void beginContact(Contact contact) {
			// TODO Auto-generated method stub

		}

		@Override
		public void endContact(Contact contact) {
			// TODO Auto-generated method stub

		}

		@Override
		public void preSolve(Contact contact, Manifold oldManifold) {
			WorldManifold worldManifold = new WorldManifold();

			contact.getWorldManifold(worldManifold);

			PointState[] state1 = new PointState[2];
			PointState[] state2 = new PointState[2];

			Collision.getPointStates(state1, state2, oldManifold, contact.getManifold());

			if (state2[0] == PointState.ADD_STATE) {
				Body bodyA = contact.getFixtureA().getBody();
				Body bodyB = contact.getFixtureB().getBody();
				Billboard bbA = (Billboard) bodyA.getUserData();
				Billboard bbB = (Billboard) bodyB.getUserData();

				Vec2 point = worldManifold.points[0];

				Vec2 vA = bodyA.getLinearVelocityFromLocalPoint(point);
				Vec2 vB = bodyB.getLinearVelocityFromLocalPoint(point);

				float approachVelocity = Math.abs(Vec2.dot(vB.sub(vA), worldManifold.normal));
				
				if (approachVelocity > 1.0f) {
					System.out.println("CRASH!" + approachVelocity);

					if(bbA.isBreakable()){
						bbA.currHitPoints -= approachVelocity;
					}
					
					if(bbB.isBreakable()){
						bbB.currHitPoints -= approachVelocity;
					}
				}
			}
		}

		@Override
		public void postSolve(Contact contact, ContactImpulse impulse) {
			// TODO Auto-generated method stub

		}
	}

}
